package edu.fdzc.project.utils;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.Date;
import java.util.UUID;

/**
 * JWT工具类
 */
public class JwtUtil {

    // 令牌标识符
    private static final String HEADER = "Authorization";

    // 令牌有效期（默认1天）
    private static final Long ACCESS_EXPIRE = 60L * 60 * 24;

    // 令牌密钥
    private static final String SECRET = "Diana_is_invited_to_tea_with_tragic_results";

    // 加密后的密钥
    private static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());

    /**
     * 创建JWT令牌
     *
     * @param userId 用户ID
     * @return 生成的JWT令牌字符串
     */
    public static String createToken(Long userId, String role) {
        return Jwts.builder()
                // header
                .header()
                .add("typ", "JWT") // 令牌类型
                .add("alg", "HS256") // 签名算法
                .and()
                // payload
                .claim("id", userId) // 用户ID
                .claim("role", role) // 用户角色
                .id(UUID.randomUUID().toString()) // JWT的唯一标识
                .expiration(Date.from(Instant.now().plusSeconds(ACCESS_EXPIRE))) // 令牌过期时间
                // signature
                .signWith(KEY, Jwts.SIG.HS256) // 签名
                .compact(); // 生成令牌字符串
    }

    /**
     * 解析JWT令牌
     *
     * @param token JWT令牌字符串
     * @return 解析后的Claims对象，包含令牌中的负载信息；如果令牌无效，返回null
     */
    public static Claims parseToken(String token) {
        try {
            return Jwts.parser()
                    .verifyWith(KEY)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取JWT令牌
     *
     * @return JWT令牌字符串；如果无法获取，则抛出运行时异常
     */
    public static String getToken() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(attributes == null) {
            throw new RuntimeException("无法从当前线程获取属性");
        }
        HttpServletRequest request = attributes.getRequest();
        return request.getHeader(HEADER);
    }

    /**
     * 获取用户ID
     *
     * @return 用户ID
     * @throws RuntimeException 如果未携带令牌或无法从当前线程获取请求属性，则抛出运行时异常
     */
    public static Long getUserId() {
        String token = getToken();
        if(token == null) {
            throw new RuntimeException("未携带token！或头属性名不为：" + HEADER);
        }
        Claims claims = parseToken(token);
        return Long.parseLong(String.valueOf(claims.get("id")));
    }

    /**
     * 获取用户角色
     *
     * @return 用户角色
     * @throws RuntimeException 如果未携带令牌或无法从当前线程获取请求属性，则抛出运行时异常
     */
    public static String getUserRole() {
        String token = getToken();
        if(token == null) {
            throw new RuntimeException("未携带token！或头属性名不为：" + HEADER);
        }
        Claims claims = parseToken(token);
        return String.valueOf(claims.get("role"));
    }

}

